﻿#include "FITKAbaqusAdaptorInteraction.h"
#include "InpKeyLineSpliter.h"
#include "FITKAbaqusINPReader.h"
#include "FITKAbaqusINPWriter.h"
#include "FITK_Component/FITKAbaqusData/FITKDataCase.h"
#include "FITK_Component/FITKAbaqusData/FITKAbaqusPart.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKBoundaryLocation.h"
#include "FITK_Interface/FITKInterfaceModel/FITKModelSet.h"
#include "FITK_Interface/FITKInterfaceModel/FITKMeshSurface.h"
#include "FITK_Interface/FITKInterfaceModel/FITKComponentManager.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaConstraintCoupling.h" 
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaConstraintTie.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAssembly.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAbstractInteraction.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionSurfToSurfExplicit.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionGeneralContactExplicit.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionManager.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionPropertyManager.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionPropertyContact.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionContactTangentialBehavior.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionContactBehavior.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionSurfToSurfExplicit.h"

#include "FITK_Interface/FITKInterfaceStructural/FITKAbaStepManager.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaStepInit.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAbstractStep.h"

//命名空间
namespace IO
{
    QString FITKAbaqusAdaptorInteraction::getAdaptorClass()
    {
        return "IO::FITKAbaqusAdaptorInteraction";
    }

    void FITKAbaqusAdaptorInteraction::setCaseData(AbaqusData::FITKDataCase* caseData)
    {
        if (caseData == nullptr) return;
        _caseData = caseData;
        tool.setCaseData(caseData);
        _interactionPropertyManager = _caseData->getInteractionPropertyManager();
    }

    void FITKAbaqusAdaptorInteraction::setStepData(Interface::FITKAbaAbstractStep* stepData)
    {
        if (stepData == nullptr) return;
        _stepData = stepData;
    }

    bool FITKAbaqusAdaptorInteraction::adaptR()
    {
        _iteractionData = dynamic_cast<Interface::FITKAbaAbstractInteraction*>(_dataObj);
        if (!_iteractionData || !_reader || !_caseData || !_interactionPropertyManager || !_stepData) return false;

        //回退一行 处理关键字信息
        _reader->backLine();

        QString line = _reader->getCurrentLine();
        if (!line.toLower().startsWith("*contact")) return false;
        //关键字处理
        InpKeyLineSpliter s(line, _reader);
        //QString partname = s["name"];
        //_iteractionData->setDataObjectName(partname);
        while (!_reader->atEnd())
        {
            bool readOK = false;
            line = _reader->readLine();
            //退出条件
            if (line.startsWith("**")) return true;

            s.reset(line);
            QString sH = s.getHeader().toLower();
            //发送计算进度信号
            _reader->sendCurrentPercent();
            //有不支持的关键字 异常退出
            //if (sH.isEmpty()) return false;
            if (sH == "contact")
            {
                //通用接触
                readOK = readContact();
            }
            else if (sH == "contact pair") //面面接触
            {
                readOK = readContactPair();
            }

            if (readOK)
            {
                //_reader->backLine();
            }
            else
            {
                return false;
            }
        }
        return false;
    }

    bool FITKAbaqusAdaptorInteraction::adaptW()
    {
        _iteractionData = dynamic_cast<Interface::FITKAbaAbstractInteraction*>(_dataObj);
        if (!_iteractionData || !_writer || !_caseData || !_interactionPropertyManager || !_stepData) return false;

        bool isW = true;

        if (_iteractionData->getInteractionType() == Interface::FITKAbaAbstractInteraction::FITKAbaInteractionType::SurfToSurfContactExplicit)
        {
            isW &= writeContactPair();
        }
        else if (_iteractionData->getInteractionType() == Interface::FITKAbaAbstractInteraction::FITKAbaInteractionType::GeneralContactExplicit)
        {
            isW &= writeContact();
            if (_iteractionData->getDeactiveStep() == _stepData->getDataObjectID()) return true;
            isW &= writeContactInclusions();
            isW &= writeContactPropertyAssignment();
        }
        return isW;
    }
    bool FITKAbaqusAdaptorInteraction::readContact()
    {
        auto generalContactExplicitData = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(_dataObj);
        if (generalContactExplicitData == nullptr) return false;

        QString line = _reader->previousLine();
        InpKeyLineSpliter s(line, _reader);
        //可选参数
        QString op = s["op"];
        if (op.toLower() == "new")
        {
            //设置取消激活的stepid
            Interface::FITKAbaInteractionManager* interactionManager = _caseData->getInteractionManager();
            if (!interactionManager)return false;
            int count = interactionManager->getDataCount();
            for (int i = 0; i < count; ++i)
            {
                Interface::FITKAbaInteractionGeneralContactExplicit* interactionData = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(interactionManager->getDataByIndex(i));
                if (!interactionData || interactionData->getCreatedStep() == _stepData->getDataObjectID() || interactionData->getDataObjectID() == _dataObj->getDataObjectID())continue;
                interactionData->setDeactiveStep(_stepData->getDataObjectID());
            }
        }
        //设置创建的stepid
        generalContactExplicitData->setCreatedStep(_stepData->getDataObjectID());
        //设置激活
        generalContactExplicitData->setActiveState(true);

        while (!_reader->atEnd())
        {
            bool readOK = false;
            line = _reader->readLine();
            //退出条件
            if (line.startsWith("**"))
            {
                _reader->backLine();
                return true;
            }

            s.reset(line);
            QString sH = s.getHeader().toLower();
            if (sH == "contact inclusions")
            {
                readOK = readContactInclusions();
            }
            else if (sH == "contact exclusions")
            {

            }
            else if (sH == "contact property assignment")
            {
                readOK = readContactPropertyAssignment();
            }
            if (!readOK)
                return false;
        }
        
        return true;
    }

    bool FITKAbaqusAdaptorInteraction::readContactPair()
    {
        auto surfExplicitData = dynamic_cast<Interface::FITKAbaInteractionSurfToSurfExplicit*>(_dataObj);
        if (surfExplicitData == nullptr) return false;

        QString line = _reader->previousLine();
        InpKeyLineSpliter s(line, _reader);

        //可选参数
        QString op = s["op"];
        QString cpset = s["cpset"];
        QString interaction = s["interaction"];
        //力学约束公式
        QString mechanicalConstraint = s["mechanical constraint"];
        //是否使用小滑移公式
        bool isSmallSliding = s.hasKey("small sliding");
        //权重系数
        QString weight = s["weight"];

        //设置相互作用属性ID
        if (!interaction.isEmpty())
        {
            auto dataObj = _interactionPropertyManager->getDataByName(interaction);
            int propertyID = dataObj->getDataObjectID();
            surfExplicitData->setContactPropertyId(propertyID);
        }

        //设置力学约束公式
        if (mechanicalConstraint == "KINEMATIC")
        {
            surfExplicitData->setMachanicalConstraintFormulation(Interface::FITKAbaInteractionSurfToSurfExplicit::MachanicalConstraintFormulation::KinematicContactMethod);
        }
        else if (mechanicalConstraint == "PENALTY")//默认
        {
            surfExplicitData->setMachanicalConstraintFormulation(Interface::FITKAbaInteractionSurfToSurfExplicit::MachanicalConstraintFormulation::PenaltyContactMethod);
        }

        //设置面面相互作用的两个面
        if (!cpset.isEmpty())
        {
            //surfExplicitData->setDataObjectName(cpset); //移动到外层设置
            QString cpSetLine = _reader->readLine();
            if (cpSetLine.startsWith("*")) return false;//异常检测
            QString L1, L2;
            QStringList locList = cpSetLine.split(',');
            if (locList.size() == 2) //如果只有一个则是自接触 目前不支持
            {
                L1 = locList[0].simplified();
                L2 = locList[1].simplified();
            }
            else
            {
                _writer->consoleMessage(3, QString("Self-contact is not supported yet. %1,%2").arg(__FILE__).arg(__LINE__));
                //自接触
                return false;
            }

            int firstModelID, secondModelID;
            int firstSurfID = tool.getSurfIDByName(L1, 1, firstModelID);
            int secondSurfID = tool.getSurfIDByName(L2, 1, secondModelID);
            //获取第一个点 设置参数
            auto firstLoc = surfExplicitData->getFirstLocation();
            firstLoc->setModel(firstModelID);
            firstLoc->setDataObjectName(L1);
            firstLoc->setComponent(firstSurfID);

            //获取第二个点 设置参数
            auto secondLoc = surfExplicitData->getSecondLocation();
            secondLoc->setModel(secondModelID);
            secondLoc->setDataObjectName(L2);
            secondLoc->setComponent(secondSurfID);
        }

        if (op == "DELETE")
        {
            surfExplicitData->setActiveState(false);
        }
        else if (op == "ADD")//默认
        {

        }

        //滑移公式 小滑移 有限滑移
        auto small = isSmallSliding ? Interface::FITKAbaAbstractInteraction::SlidingFormulation::SmallSliding : 
            Interface::FITKAbaAbstractInteraction::SlidingFormulation::FinitSliding;
        surfExplicitData->setSlidingFormulation(small);

        //设置权重系数方式
        if (!weight.isEmpty())
        {
            surfExplicitData->setWeightingFactor(Interface::FITKAbaInteractionSurfToSurfExplicit::WeightingFactor::Specify);
            double weightD = weight.toDouble();
            //判断值错误 一般用不到
            if (weightD < 0 && weightD > 1) _writer->consoleMessage(3, QString("Read Interaction WeightD Error, WeightD Value Error. %1,%2").arg(__FILE__).arg(__LINE__));
            surfExplicitData->setWeightingFactorValue(weightD);
        }

        return true;
    }

    bool FITKAbaqusAdaptorInteraction::readContactInclusions()
    {
        auto generalContactExplicitData = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(_dataObj);
        if (generalContactExplicitData == nullptr) return false;

        QString line = _reader->previousLine();
        InpKeyLineSpliter s(line, _reader);

        //可选参数
        bool allExteriorp = s.hasKey("ALL EXTERIOR");
        auto includeSurfacePairs = allExteriorp ? 
            Interface::GeneralContactExplicitData::IncludeSurfacePairs::AllWithSelf : Interface::GeneralContactExplicitData::IncludeSurfacePairs::SelectedSurfacePairs;
        //设置是否包含表面对
        generalContactExplicitData->setIncludeSurfacePairs(includeSurfacePairs);
        if (includeSurfacePairs == Interface::GeneralContactExplicitData::IncludeSurfacePairs::AllWithSelf) return true;
        bool readOk = false;
        for (int index = 0; !_reader->atEnd(); ++index)
        {
            line = _reader->readLine();
            if (line.contains("*"))break;
            //初始化数据
            generalContactExplicitData->setNumberOfIncludeSurfPairs(index + 1);
            readOk = true;
            //获取表面名称
            QStringList str = line.trimmed().split(',');
            if (str.size() != 2)return false;
            //获取第一个表面和第二个表面
            QPair<Interface::FITKBoundaryLocation*, Interface::FITKBoundaryLocation*> location = generalContactExplicitData->getIncludeSurfPair(index);
            //第一表面如果为空则所有
            int instanceId = -1, surfId = -1;
            if (!str.at(0).trimmed().isEmpty())
            {
                //获取第一表面
                surfId = tool.getSurfIDByName(str.at(0).trimmed(), Interface::FITKMeshSurface::MeshSurfaceType::SurEle, instanceId);
                if (surfId == -1)return false;
            }
            location.first->setModel(instanceId);
            location.first->setComponent(surfId);
            //第二表面如果为空则是第一个表面的自身
            if (!str.at(1).trimmed().isEmpty())
            {
                //获取第二表面
                 surfId = tool.getSurfIDByName(str.at(1).trimmed(), Interface::FITKMeshSurface::MeshSurfaceType::SurEle, instanceId);
                if (surfId == -1)return false;
            }
            location.second->setModel(instanceId);
            location.second->setComponent(surfId);
        }
        //后退一行防止数据丢失
        _reader->backLine();
        return readOk;
    }

    bool FITKAbaqusAdaptorInteraction::readContactPropertyAssignment()
    {
        auto generalContactExplicitData = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(_dataObj);
        if (generalContactExplicitData == nullptr) return false;

        QString line = _reader->readLine();
        QStringList strList = line.split(',');

        if (strList.size() < 3) return false; //目前只读了三个 全集有五个参数
        int firstModelID, secondModelID;
        QString L1 = strList[0].simplified();
        QString L2 = strList[1].simplified();
        QString L3 = strList[2].simplified();

        if (!L1.isEmpty())
        {
            //获取第一个点 设置参数
            auto firstLoc = generalContactExplicitData->getFirstLocation();
            int firstSurfID = tool.getSurfIDByName(L1, 1, firstModelID);
            firstLoc->setComponent(firstSurfID);
            firstLoc->setModel(firstModelID);
            firstLoc->setDataObjectName(L1);
        }

        if (!L2.isEmpty())
        {
            //获取第二个点 设置参数
            auto secondLoc = generalContactExplicitData->getSecondLocation();
            int secondSurfID = tool.getSurfIDByName(L2, 1, secondModelID);
            secondLoc->setComponent(secondSurfID);
            secondLoc->setModel(secondModelID);
            secondLoc->setDataObjectName(L2);
        }

        if (!L3.isEmpty())
        {
            //设置相互作用属性ID
            auto dataObj = _interactionPropertyManager->getDataByName(L3);
            int propertyID = dataObj->getDataObjectID();
            generalContactExplicitData->setContactPropertyId(propertyID);
        }

        return true;
    }


    bool FITKAbaqusAdaptorInteraction::writeContact()
    {
        auto surfExplicitData = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(_dataObj);
        if (surfExplicitData == nullptr) return false;
        QTextStream* stream = _writer->getStream();
        QString outputString;
        QString op;
        outputString += "*Contact";
        //写出op参数 通用接触只允许创建一个所以都需要带op=NEW
        outputString += ", op=NEW";
        outputString += op;
        *stream << outputString << endl;
        return true;
    }

    bool FITKAbaqusAdaptorInteraction::writeContactPair()
    {
        auto surfExplicitData = dynamic_cast<Interface::FITKAbaInteractionSurfToSurfExplicit*>(_dataObj);
        if (surfExplicitData == nullptr) return false;
        QTextStream* stream = _writer->getStream();
        QString outputString;
        outputString += "*Contact Pair";

        if (surfExplicitData->getDeactiveStep() != _stepData->getDataObjectID())
        {
            int propertyID = surfExplicitData->getContactPropertyId();
            auto _interactionProperty = _interactionPropertyManager->getDataByID(propertyID);
            if (_interactionProperty == nullptr) return false;
            QString interPropName = _interactionProperty->getDataObjectName();
            interPropName = interPropName.contains(' ') ? QString("\"%1\"").arg(interPropName) : interPropName;
            outputString += QString(", interaction=%1").arg(interPropName);

            //设置力学约束公式
            auto mechanicalConstraint = surfExplicitData->getMachanicalConstraintFormulation();
            if (mechanicalConstraint == Interface::FITKAbaInteractionSurfToSurfExplicit::MachanicalConstraintFormulation::KinematicContactMethod)
            {
                outputString += QString(", mechanical constraint=%1").arg("KINEMATIC");
            }
            else if (mechanicalConstraint == Interface::FITKAbaInteractionSurfToSurfExplicit::MachanicalConstraintFormulation::PenaltyContactMethod)
            {
                outputString += QString(", mechanical constraint=%1").arg("PENALTY");
            }

            //写出权重系数
            if (surfExplicitData->getWeightingFactor() == Interface::FITKAbaInteractionSurfToSurfExplicit::WeightingFactor::Specify)
            {
                double weightD = surfExplicitData->getWeightingFactorValue();
                outputString += QString(", weight=%1").arg(_writer->double2String(weightD, 9, 0));
            }
        }
        else
        {
            outputString += QString(", op=DELETE");
        }

        QString name = surfExplicitData->getDataObjectName();
        if (!name.isEmpty())
        {
            name = name.contains(' ') ? QString("\"%1\"").arg(name) : name;
            outputString += QString(", cpset=%1").arg(name);
        }
        *stream << outputString << endl;

        //最后一个参数需要换行
        //获取第一个点 设置参数
        auto firstLoc = surfExplicitData->getFirstLocation();
        //获取第二个点 设置参数
        auto secondLoc = surfExplicitData->getSecondLocation();
        if (!firstLoc || !secondLoc) return false;
        if (firstLoc->getComponentObj() == nullptr) return false;
        QString firstLocName = firstLoc->getComponentObj()->getDataObjectName();
        if (secondLoc->getComponentObj() == nullptr) return false;
        QString secondLocName = secondLoc->getComponentObj()->getDataObjectName();
        firstLocName = firstLocName.contains(' ') ? QString("\"%1\"").arg(firstLocName) : firstLocName;
        secondLocName = secondLocName.contains(' ') ? QString("\"%1\"").arg(secondLocName) : secondLocName;
        *stream << QString("%1, %2").arg(firstLocName).arg(secondLocName) << endl;
        return true;
    }

    bool FITKAbaqusAdaptorInteraction::writeContactInclusions()
    {
        auto generalContactExplicitData = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(_dataObj);
        if (generalContactExplicitData == nullptr) return false;
        QTextStream* stream = _writer->getStream();
        QString outputString;
        outputString += "*Contact Inclusions";
        int stepId = _stepData->getDataObjectID();
        if (generalContactExplicitData->getIncludeSurfacePairs() == Interface::GeneralContactExplicitData::IncludeSurfacePairs::AllWithSelf)
        {
            outputString += QString(", ALL EXTERIOR");
            *stream << outputString << endl;
        }
        else if (generalContactExplicitData->getIncludeSurfacePairs(stepId) == Interface::GeneralContactExplicitData::IncludeSurfacePairs::SelectedSurfacePairs)
        {
            *stream << outputString << endl;
            int count = generalContactExplicitData->getNumberOfIncludeSurfPairs(stepId);
            for (int i = 0; i < count; ++i)
            {
                //获取第一个表面和第二个表面
                QPair<Interface::FITKBoundaryLocation*, Interface::FITKBoundaryLocation*> location = generalContactExplicitData->getIncludeSurfPair(i, stepId);
                //写出第一个面
                QString setNameFirst;
                auto setFirst = location.first->getComponentObj();
                if (setFirst) setNameFirst = setFirst->getDataObjectName();
                setNameFirst = setNameFirst.contains(' ') ? QString("\"%1\"").arg(setNameFirst) : setNameFirst;
                if (location.first->getModelObj() && location.first->getModelObj()->getAbsModelType() != Interface::FITKModelEnum::AbsModelType::Assembly)
                {
                    QString name = location.first->getModelObj()->getDataObjectName();
                    name = name.contains(' ') ? QString("\"%1\"").arg(name) : name;
                    setNameFirst = QString("%1.%2").arg(name).arg(setNameFirst);
                }
                //写出第二个面
                QString setNameSecond;
                auto setSecond = location.second->getComponentObj();
                if (setSecond && setFirst->getDataObjectID() != setSecond->getDataObjectID()) setNameSecond = setSecond->getDataObjectName();
                setNameSecond = setNameSecond.contains(' ') ? QString("\"%1\"").arg(setNameSecond) : setNameSecond;
                if (!setNameSecond.isEmpty() && location.second->getModelObj() && location.second->getModelObj()->getAbsModelType() != Interface::FITKModelEnum::AbsModelType::Assembly)
                {
                    QString name = location.second->getModelObj()->getDataObjectName();
                    name = name.contains(' ') ? QString("\"%1\"").arg(name) : name;
                    setNameSecond = QString("%1.%2").arg(name).arg(setNameSecond);
                }
                *stream << QString("%1 , %2").arg(setNameFirst).arg(setNameSecond) << endl;
            }
            //outputString += QString(", ALL EXTERIOR");
        }
        
        return true;
    }

    bool FITKAbaqusAdaptorInteraction::writeContactPropertyAssignment()
    {
        auto generalContactExplicitData = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(_dataObj);
        if (generalContactExplicitData == nullptr) return false;
        QTextStream* stream = _writer->getStream();
        QString outputString;
        QString L1, L2, L3;
        outputString += "*Contact Property Assignment";
        int stepId = _stepData->getDataObjectID();
        //获取第一个点 设置参数
        auto firstLoc = generalContactExplicitData->getFirstLocation();
        //获取第二个点 设置参数
        auto secondLoc = generalContactExplicitData->getSecondLocation();
        if (!firstLoc || !secondLoc) return false;
        if (!L3.isEmpty())
        {
            //设置相互作用属性ID
            auto dataObj = _interactionPropertyManager->getDataByName(L3);
            if (!dataObj) return false;
            int propertyID = dataObj->getDataObjectID();
            generalContactExplicitData->setContactPropertyId(propertyID);
        }

        auto firstModel = firstLoc->getModelObj();
        if (firstModel != nullptr)
        {
            L1 = firstModel->getDataObjectName();
            L1 = L1.contains(' ') ? QString("\"%1\"").arg(L1) : L1;
        }
        auto secondModel = secondLoc->getModelObj();
        if (secondModel != nullptr)
        {
            L2 = secondModel->getDataObjectName();
            L2 = L2.contains(' ') ? QString("\"%1\"").arg(L2) : L2;
        }
        //如果是空 则用空格补位
        if (L2.isEmpty())L2 = " ";

        int propertyID = generalContactExplicitData->getContactPropertyId(stepId);
        auto _interactionProperty = _interactionPropertyManager->getDataByID(propertyID);
        if (_interactionProperty == nullptr) return false;
        L3 = _interactionProperty->getDataObjectName();
        L3 = L3.contains(' ') ? QString("\"%1\"").arg(L3) : L3;
        *stream << outputString << endl;
        *stream << QString(" %1, %2, %3").arg(L1).arg(L2).arg(L3) << endl;
        return true;
    }
}